package com.yuexia.yxim.server.server;

import com.yuexia.yxim.common.bean.msg.ProtoMsg;
import com.yuexia.yxim.common.bean.msg.User;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.util.AttributeKey;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.server.Session;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

/**
 * @Author: yue_xia
 * @Date: 2020/6/2 9:55 下午
 */
@Data
@Slf4j
public class ServerSession {

    private String sessionId;

    private Channel channel;
    private User user;

    private boolean isLogin = false;

    public static final AttributeKey<String> KEY_USER_ID =
            AttributeKey.valueOf("key_user_id");

    public static final AttributeKey<ServerSession> SESSION_KEY =
            AttributeKey.valueOf("SESSION_KEY");

    private Map<String, Object> map = new HashMap<>();

    public ServerSession(Channel channel) {
        this.channel = channel;
        this.sessionId = buildNewSessionId();
    }

    //反向导航
    public static ServerSession getSession(ChannelHandlerContext ctx) {
        Channel channel = ctx.channel();
        return channel.attr(ServerSession.SESSION_KEY).get();
    }

    /**
     * 构造session id
     * @return
     */
    private String buildNewSessionId() {
        String uuid = UUID.randomUUID().toString();
        return uuid.replace("-", "");
    }

    /**
     * 关闭连接
     * @param ctx
     */
    public static void closeSession(ChannelHandlerContext ctx) {
        ServerSession serverSession = ctx.channel().attr(ServerSession.SESSION_KEY).get();
        if (null != serverSession && serverSession.isValid()) {
            serverSession.close();
            SessionMap.inst().removeSession(serverSession.getSessionId());
        }
    }

    private void close() {
        ChannelFuture channelFuture = channel.close();
        channelFuture.addListener(new ChannelFutureListener() {
            @Override
            public void operationComplete(ChannelFuture channelFuture) throws Exception {
                if (!channelFuture.isSuccess()) {
                    log.error("CHANNEL_CLOSED error ");
                }
            }
        });
    }

    private boolean isValid() {
        return getUser() != null;
    }

    /**
     * 写proto部分数据帧
     * @param responce
     */
    public synchronized void writeAndFlush(Object responce) {
        channel.writeAndFlush(responce);
    }

    //和通道实现双向绑定
    public ServerSession bind() {

        log.info("serversession绑定会话 " + channel.remoteAddress());

        channel.attr(ServerSession.SESSION_KEY).set(this);
        SessionMap.inst().addSession(getSessionId(), this);
        isLogin = true;
        return this;
    }

    public ServerSession unBind() {
        isLogin = false;
        SessionMap.inst().removeSession(getSessionId());
        this.close();
        return this;
    }

    public synchronized void set(String key, Object value) {
        map.put(key, value);
    }

    public synchronized <T> T get(String key) {
        return (T)map.get(key);
    }
    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
        user.setSessionId(sessionId);
    }
}
